//Pietras93OS
//Memory manager 
//pietras93@gmail.com
//

#include <system.h>

typedef struct
{
   void *address;
   long  length;
} mment_t;

mment_t mmtable[1000];
mment_t used[1000];
int mm_len, used_len;

void init_mm()
{
   int totalmem;
   outportb(0x70,0x17);
   totalmem = inportb(0x71);
   outportb(0x70,0x18);
   totalmem = (totalmem + (inportb(0x71) << 8)) * 1024;
   mmtable[0].address = (void *)0x200000;
   mmtable[0].length  = totalmem - 0x200000;
   mm_len = 1;
   puts("Memory Manager started!");
}

int mm_count(void)
{
        register unsigned long *mem;
        unsigned long   mem_count, a, mem_end, bse_end;
        unsigned short  memkb;
        unsigned char   irq1, irq2;
        unsigned long   cr0;

        // save IRQ's
        irq1=inportb(0x21);
        irq2=inportb(0xA1);

        // kill all irq's
        outportb(0x21, 0xFF);
        outportb(0xA1, 0xFF);

        mem_count=0;
        memkb=0;

        // store a copy of CR0
        __asm__ __volatile__("movl %%cr0, %0":"=r"(cr0));

        // invalidate the cache
        // write-back and invalidate the cache
        __asm__ __volatile__("wbinvd");

        // plug cr0 with just PE/CD/NW
        // cache disable(486+), no-writeback(486+), 32bit mode(386+)
        __asm__ __volatile__("movl %0, %%cr0": :"r"(cr0 | 0x00000001 | 0x40000000 | 0x20000000));

        do
        {
                memkb++;
                mem_count+=1024*1024;
                mem=(unsigned long*)mem_count;

                a=*mem;

                *mem=0x55AA55AA;

                asm("":::"memory");
                if(*mem!=0x55AA55AA)
                    mem_count=0;
                else
                {
                        *mem=0xAA55AA55;
                        asm("":::"memory");
                        if(*mem!=0xAA55AA55)
                            mem_count=0;
                }

                asm("":::"memory");
                *mem=a;
        }
        while(memkb<4096 && mem_count!=0);

        __asm__ __volatile__("movl %0, %%cr0": :"r"(cr0));

        mem_end=memkb<<20;
        mem=(unsigned long*)0x413;
        bse_end=((*mem)&0xFFFF)<<6;

        outportb(0x21,irq1);
        outportb(0xA1,irq2);

        return memkb;
}

void *malloc(long size)
{
   int i, j;
   void *retval;
   for(i = 0; i < mm_len; i++)
   {
      if(mmtable[i].length >= size)
         break;
   }
   if(i == mm_len)
      return 0;
   retval = mmtable[i].address;
   mmtable[i].address  += size;
   mmtable[i].length   -= size;
   if(mmtable[i].length == 0)
   {
      for(j = i; i < mm_len - 1; j++)
      {
         mmtable[j] = mmtable[j + 1];
      }
      mm_len--;
   }
   used[used_len].address = retval;
   used[used_len].length  = size;

   return retval;
}

void free(void *address)
{
   address = 0;
}

void *realloc(void *address, int size)
{
   void *retval = malloc(size);
   int old_size, i;
   for(i = 0; used[i].address != address; i++);
   old_size = used[i].length;
   memcpy(retval, address, old_size);
   free(address);
   return retval;
}

void *calloc(int num, int size)
{
   return malloc(num * size);
}

/*void show_memory()
{
   unsigned char highmem, lowmem;
   unsigned int mem;
   // need to stop ints before accessing the CMOS chip
   cli();
   // write to port 0x70 with the CMOS register we want to read
   // 0x30 is the CMOS reg that hold the low byte of the mem count
   outportb(0x70,0x30);
   // read CMOS values from port 0x71
   lowmem = inportb(0x71);
   // write to port 0x70 with the CMOS register we want to read
   // 0x31 is the CMOS reg that hold the high byte of the mem count
   outportb(0x70,0x31);
   // read CMOS values from port 0x71
   highmem = inportb(0x71);
   sti();
   // fix the low and high bytes into one value
   mem = highmem;
   mem = mem<<8;
   mem += lowmem;

   printf("%uK total conventional memory\n", mem);
}*/
